package com.doc.desensitization.common.utils;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.util.Collection;

/**
 * 脱敏切面
 */
@Aspect
@Component
@Slf4j
public class DesensitizationAspect {
    /**
     * 拦截service包下的所有方法
     */
    @Pointcut("execution(* *(..)) && @within(org.springframework.stereotype.Service)")
    public void serviceFiledPointcut() {
    }

    /**
     * 拦截所有被 @Desensitize 注解标记的方法
     */
    @Pointcut("@annotation(Desensitize)")
    public void controllerFiledPointcut() {
    }
    @Around("serviceFiledPointcut() || controllerFiledPointcut()")
    public Object desensitizeAround(ProceedingJoinPoint joinPoint) throws Throwable {
        Object result = joinPoint.proceed();
        // 对返回结果进行脱敏处理
        if (result != null) {
            processDesensitization(result);
        }
        return result;
    }
    /**
     * 处理对象的脱敏
     */
    private void processDesensitization(Object object) throws IllegalAccessException {
        log.info("开始对返回结果进行脱敏处理");
        if(object == null) return;
        //判断是否是集合
        if(object instanceof Collection<?>){
            //遍历集合,递归调用得到集合中的元素
            for (Object item : (Collection<?>) object) {
                processDesensitization(item);
            }
            return;
        }
        //判断是否是集合
        if(object.getClass().isArray()){
            // 获取数组元素类型
            Class<?> componentType = object.getClass().getComponentType();

            // 如果是基本类型数组（如 byte[]），直接返回
            if (componentType.isPrimitive()) {
                return;
            }

            // 如果是对象数组，正常处理
            Object[] array = (Object[]) object;
            for (Object item : array) {
                processDesensitization(item);
            }
            return;
        }
        //接下来全是单个对象
        Class<?> clazz = object.getClass();
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);
          //检查字段是否有脱敏注解
            if(field.isAnnotationPresent(Desensitize.class)){
                Desensitize desensitize = field.getAnnotation(Desensitize.class);
                Object value = field.get(object);
                // 只处理字符串类型的字段
                if (value instanceof String) {
                    String newValue = DesensitizationUtil.desensitize(
                            (String) value, desensitize.type(), desensitize.prefixLength(), desensitize.suffixLength());
                    // 设置新的值
                    field.set(object, newValue);
                }
            }else{
                // 递归处理对象类型的字段
                Object value = field.get(object);
                if (value != null && !isPrimitiveOrWrapper(value.getClass())) {
                    processDesensitization(value);
                }
            }
        }
        log.info("结束对返回结果进行脱敏处理");
    }

    /**
     * 判断是否是基本类型或包装类型
     */
    private boolean isPrimitiveOrWrapper(Class<?> clazz) {
        return clazz.isPrimitive() ||
                clazz == Integer.class ||
                clazz == Long.class ||
                clazz == Float.class ||
                clazz == Double.class ||
                clazz == Boolean.class ||
                clazz == Character.class ||
                clazz == Byte.class ||
                clazz == Short.class ||
                clazz == String.class;
    }
}
